using System;
using System.Collections;
using System.Collections.Generic;
using Main.Details;
using Main.Event;
using Main.Save;
using UnityEngine;
using ZSW.Framework;

namespace Main
{
    public class Player : ZSWF_InitMonoBehaviour, ISaveable
    {
        public static Transform Transform
        {
            get
            {
                if (selfTransform == null)
                {
                    selfTransform = FindObjectOfType<Player>().transform;
                }
                return selfTransform;
            }
        }

        public string GUID => GetComponent<DataGUID>().guid;

        private static Transform selfTransform;

        [SerializeField] private Rigidbody2D rb;
        [SerializeField] private float speed;
        [SerializeField] private Vector2 input;
        private Animator[] animators;
        private bool isMoving;
        private bool allowInput;
        // Tool动画输入
        private float mouseX;
        private float mouseY;
        private bool useTool;
        public override void Init()
        {
            base.Init();
            rb = GetComponent<Rigidbody2D>();
            animators = GetComponentsInChildren<Animator>();

            rb.drag = 5f;

            ISaveable saveable = this;
            saveable.RegisterSaveable();
        }

        private void OnEnable()
        {
            MainEventSystem.BeforeLoadSceneEvent += OnBeforeLoadScene;
            MainEventSystem.AfterLoadSceneEvent += OnAfterLoadScene;
            MainEventSystem.MoveToPosition += OnMoveToPosition;
            MainEventSystem.MouseClickedEvent += OnMouseClicked;
            MainEventSystem.UpdateGameStateEvent += OnUpdateGameState;
            MainEventSystem.StartNewGameEvent += OnStartNewGame;
        }

        private void OnDisable()
        {
            MainEventSystem.BeforeLoadSceneEvent -= OnBeforeLoadScene;
            MainEventSystem.AfterLoadSceneEvent -= OnAfterLoadScene;
            MainEventSystem.MoveToPosition -= OnMoveToPosition;
            MainEventSystem.MouseClickedEvent -= OnMouseClicked;
            MainEventSystem.UpdateGameStateEvent -= OnUpdateGameState;
            MainEventSystem.StartNewGameEvent -= OnStartNewGame;
        }

        private void OnStartNewGame(int obj)
        {
            allowInput = false;
            transform.position = Settings.PlayerStartPos;
        }

        private void Update()
        {
            if (allowInput)
            {
                PlayerInput();
            }
            else
            {
                isMoving = false;
            }
            SwitchAnimation();
        }

        private void FixedUpdate()
        {
            if (allowInput)
            {
                Movement();
            }
        }

        private void OnUpdateGameState(GameState state)
        {
            switch (state)
            {
                case GameState.GamePlay:
                    allowInput = true;
                    break;
                case GameState.Pause:
                    allowInput = false;
                    break;
            }
        }

        private void OnMouseClicked(Vector3 mouseWorldPos, ItemDetails item)
        {
            // TODO: player动画 
            Debug.Log("OnMouseClicked");

            if (item.ItemType.IsTool())
            {
                mouseX = mouseWorldPos.x - transform.position.x;
                mouseY = mouseWorldPos.y - transform.position.y + 0.85f;

                if (Mathf.Abs(mouseX) > Mathf.Abs(mouseY))
                {
                    mouseY = 0;
                }
                else
                {
                    mouseX = 0;
                }

                StartCoroutine(UseToolRoutine(mouseWorldPos, item));
            }
            else
            {
                MainEventSystem.CallExecuteActionAfterAnimation(mouseWorldPos, item);
            }
        }

        private IEnumerator UseToolRoutine(Vector3 mouseWorldPos, ItemDetails item)
        {
            useTool = true;
            allowInput = false;
            yield return null;
            foreach (var anim in animators)
            {
                anim.SetTrigger("UseTool");
                anim.SetFloat("InputX", mouseX);
                anim.SetFloat("InputY", mouseY);
            }
            yield return new WaitForSeconds(0.45f);
            MainEventSystem.CallExecuteActionAfterAnimation(mouseWorldPos, item);
            yield return new WaitForSeconds(0.25f);

            useTool = false;
            allowInput = true;
        }

        private void OnBeforeLoadScene()
        {
            allowInput = false;
        }

        private void OnAfterLoadScene()
        {
            allowInput = true;
        }

        private void OnMoveToPosition(Vector3 position)
        {
            transform.position = position;
        }

        private void PlayerInput()
        {
            float multiplier = Input.GetKey(KeyCode.LeftShift) ? 1 : 0.5f;

            input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")).normalized * multiplier;

            isMoving = input != Vector2.zero;
        }

        private void Movement()
        {
            rb.MovePosition(rb.position + input * speed * Time.fixedDeltaTime);
        }

        public void SwitchAnimation()
        {
            foreach (var anim in animators)
            {
                anim.SetBool("IsMoving", isMoving);
                anim.SetFloat("MouseX", mouseX);
                anim.SetFloat("MouseY", mouseY);
                if (isMoving)
                {
                    anim.SetFloat("InputX", input.x);
                    anim.SetFloat("InputY", input.y);
                }
            }
        }

        public GameSaveData GenerateSaveData()
        {
            GameSaveData saveData = new GameSaveData();
            saveData.CharacterPosDict = new Dictionary<string, SerializableVector3>();
            saveData.CharacterPosDict.Add(this.name, new SerializableVector3(transform.position));

            return saveData;
        }

        public void RestoreData(GameSaveData data)
        {
            var targetPosition = data.CharacterPosDict[this.name].ToVector3();

            transform.position = targetPosition;
        }
    }

}